#include <stdio.h>
#include <avr/io.h>
#include <avr/delay.h>

#define LEDS_SUPERIOR 0xF0
#define TIME 100


void right_to_left_single_led(void);
void left_to_right_single_led(void);
void increment_left_same_order(void);
void increment_right_same_order(void);
void increment_left_inverse_order(void);
void increment_right_inverse_order(void);
void scrolling_single_led(void);
void custom_mode(void);


int
main (void) {

	unsigned char aux = 0xFF;
	int key = 0;

	DDRD = 0xFF;
	DDRB = 0x00;

	while (1) {

		aux = PINB;
		if (aux != 0xFF) {
			key = aux;
			_delay_ms(300);
		}

		switch (key) {
			case 0xFE:
				right_to_left_single_led();
				break;
			case 0xFD:
				left_to_right_single_led();
				break;
			case 0xFB:
				increment_left_same_order();
				break;
			case 0xF7:
				increment_right_same_order();
				break;
			case 0xEF:
				increment_left_inverse_order();
				break;
			case 0xDF:
				increment_right_inverse_order();
				break;
			case 0xBF:
				scrolling_single_led();
				break;
			case 0x7F:
				custom_mode();
				break;
			default:
				break;
		}
	}
}

void
right_to_left_single_led(void) {

	int i,
	value = 0x01;
	for(i=0; i<8; i++) {
		PORTD = ~value;
		value = (value << 1);
		_delay_ms(TIME);
	}
	PORTD = 0xFF;
}

void
left_to_right_single_led(void) {

	int i,
	value = 0x80;
	for(i=0; i<8; i++) {
		PORTD = ~value;
		value = (value >> 1);
		_delay_ms(TIME);
	}
	PORTD = 0xFF;
}

void
increment_left_same_order(void) {

	int i,
	value = 0xFF;
	for(i=0; i<8; i++) {
		PORTD = value;
		value = (value << 1);
		_delay_ms(TIME);
	}
	for(i=0; i<8; i++) {
		value = (value << 1)|0x01;
		PORTD = value;
		_delay_ms(TIME);
	}
}

void
increment_right_same_order(void) {

	int i,
	value = 0xFF;
	for(i=0; i<8; i++) {
		PORTD = value;
		value = (value >> 1);
		_delay_ms(TIME);
	}
	for(i=0; i<8; i++) {
		value = (value >> 1)|0x80;
		PORTD = value;
		_delay_ms(TIME);
	}
	PORTD = 0xFF;
}

void
increment_left_inverse_order(void) {

	int i,
	value = 0xFF;
	for(i=0; i<8; i++) {
		PORTD = value;
		value = (value << 1);
		_delay_ms(TIME);
	}
	PORTD = 0xFF;
	for(i=0; i<8; i++) {
		PORTD = value;
		value = (value >> 1);
		_delay_ms(TIME);
	}
	PORTD = 0xFF;
}

void
increment_right_inverse_order(void) {

	int i,
	value = 0xFF;
	for(i=0; i<8; i++) {
		PORTD = value;
		value = (value >> 1);
		_delay_ms(TIME);
	}
	for(i=0; i<8; i++) {
		PORTD = value;
		value = (value << 1)|0x01;
		_delay_ms(TIME);
	}
	PORTD = 0XFF;
}

void
scrolling_single_led(void) {

	int i,
	value = 0x01;
	for(i=0; i<8; i++) {
		PORTD = ~value;
		value = (value << 1);
		_delay_ms(TIME);
	}
	value = 0x80;
	for(i=0; i<8; i++) {
		PORTD = ~value;
		value = (value >> 1);
		_delay_ms(TIME);
	}
	PORTD = 0XFF;
}

void
custom_mode(void) {

	int i;
	char right_value = 0x0F;
	char left_value = 0xF0;
	for(i=0; i<5; i++) {
		PORTD = right_value | left_value;
		right_value = (right_value >> 1);
		left_value = (left_value << 1);
		_delay_ms(TIME);
	}
}
